/**
 * 页面操作后的反馈小提示
 * @createDate 2022-02-18 17:31 (星期五)
 * @directory JavaScript\code-preview\js\short-tips.js
 **/

/**
 * 页面操作后的反馈小提示
 */
class ShortTips {
  /**
   * 类实例化构造函数
   * @param {Element} targetNode 需要挂载的DOM节点
   */
  constructor(targetNode) {
    // 挂载的目标节点
    this.targetNode = targetNode || document.body;
    // 短提示容器
    this.shortTipsWrapper = null;
    // 图标基本路径设置
    this.iconPath = '/images/short-tips-icons';

    /**
     * 初始化短提示
     * @param {Fuction} callback 在容器创建完成后的自义定操作函数，参数为容器本身
     */
    this.init = (callback = function () {}) => {
      this.shortTipsWrapper = document.createElement('div');
      const wrapper = this.shortTipsWrapper;
      wrapper.className = 'short-tips-wrapper';

      // 自定义操作
      callback(wrapper);
    };
  }

  /**
   * 显示短提示
   * @param {Object} options 方法调用配置项
   * - mesg {String} 提示内容
   * - duration {Number} 持续时间（毫秒）
   * - masklayer {Boolean} 是否显示遮罩层
   * @param {Function} callback 用于设置具体提示种类的设置类回调函数
   */
  show = (options, callback = function () {}) => {
    let mesgTxt = '';
    let duration = 0;
    let masklayer = false;
    // 判断option类型：对象
    if (typeof options === 'object') {
      mesgTxt = options.mesg || '<未配置>';
      duration = options.duration || 2500;
      masklayer = options.masklayer || false;
    }
    // 判断option类型：字符串
    else if (typeof options === 'string') {
      mesgTxt = options;
      duration = 2500;
      masklayer = false;
    }

    // 生成内容容器
    this.shortTipsBox = document.createElement('div');
    const mesgTextSpan = document.createElement('span');
    mesgTextSpan.textContent = mesgTxt;
    this.shortTipsBox.appendChild(mesgTextSpan);
    this.shortTipsBox.className = 'short-tips-box';

    // 生成不重复 ID 和时间戳
    const uniqID =  generateUniqueId();
    const timeStamp = new Date().getTime();
    const uniqIdent = uniqID + timeStamp;
    this.shortTipsBox.dataset.ident = uniqIdent;

    // 主包裹容器
    const mainWrapper = this.shortTipsWrapper;

    // 显示遮罩层
    options.masklayer
      ? mainWrapper.classList.add('has-masklayer')
      : mainWrapper.classList.remove('has-masklayer');

    // 执行自定义提示类型函数，返回提示框简要配置信息对象
    const tipsInfo = callback();

    // 如果为含有类型的提示框
    const typeCondition =
      tipsInfo?.type === 'info' ||
      tipsInfo?.type === 'warn' ||
      tipsInfo?.type === 'success' ||
      tipsInfo?.type === 'fail';

    // 如果其中之一满足提示类型条件
    if (typeCondition) {
      this.shortTipsBox.insertAdjacentElement('afterbegin', tipsInfo.icon);
    }

    // 为容器按层次添加子节点
    mainWrapper.appendChild(this.shortTipsBox);
    this.targetNode.appendChild(mainWrapper);

    // 延时后移除
    setTimeout(() => {
      // 当前的首个元素
      const firstMesg = mainWrapper.querySelector(
        `.short-tips-box[data-ident="${uniqIdent}"]`
      );
      firstMesg.style.marginTop = 0;
      firstMesg.style.opacity = 0;
      if (options.masklayer) {
        mainWrapper.style.opacity = 0;
      }
      // 获取容器的遮罩层状态
      setTimeout(() => {
        firstMesg.remove();
      }, 300);
    }, duration);
  };

  /**
   * 显示短提示-信息类
   * @param {Object} options 方法调用配置项
   * - mesg {String} 提示内容
   * - duration {Number} 持续时间（毫秒）
   * - masklayer {Boolean} 是否显示遮罩层
   */
  info = (options) => {
    this.show(options, (ele) => {
      const icon = document.createElement('i');
      icon.classList.add('icon-info');

      return {
        icon,
        type: 'info',
      };
    });
  };

  /**
   * 显示短提示-警告类
   * @param {Object} options 方法调用配置项
   * - mesg {String} 提示内容
   * - duration {Number} 持续时间（毫秒）
   * - masklayer {Boolean} 是否显示遮罩层
   */
  warn = (options) => {
    this.show(options, () => {
      const icon = document.createElement('i');
      icon.classList.add('icon-warn');

      return {
        icon,
        type: 'warn',
      };
    });
  };

  /**
   * 显示短提示-成功类
   * @param {Object} options 方法调用配置项
   * - mesg {String} 提示内容
   * - duration {Number} 持续时间（毫秒）
   * - masklayer {Boolean} 是否显示遮罩层
   */
  success = (options) => {
    this.show(options, () => {
      const icon = document.createElement('i');
      icon.classList.add('icon-success');

      return {
        icon,
        type: 'success',
      };
    });
  };

  /**
   * 显示短提示-失败类(错误类)
   * @param {Object} options 方法调用配置项
   * - mesg {String} 提示内容
   * - duration {Number} 持续时间（毫秒）
   * - masklayer {Boolean} 是否显示遮罩层
   */
  fail = (options) => {
    this.show(options, () => {
      const icon = document.createElement('i');
      icon.classList.add('icon-fail');

      return {
        icon,
        type: 'fail',
      };
    });
  };
}

/**
 * 生成指定位数不重复的 ID（但不能保证绝对不重复，可以配合时间戳使用）
 * @param {Number} quantity 需要生成 ID 字符的个数。默认值：8
 * @returns {String} 不重复ID
 */
function generateUniqueId(quantity = 8) {
  const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  let id = '';
  for (let i = 0; i < quantity; i++) {
    id += characters.charAt(Math.floor(Math.random() * characters.length));
  }
  return id;
}

export default ShortTips;
